// (C) 2021 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1ns / 1ps

/*
 * LFSR PRBS checker
 */
module lfsr_prbs_check #
(
    // width of LFSR
    parameter LFSR_WIDTH = 31,
    // LFSR polynomial
    parameter LFSR_POLY = 31'h10000001,
    // Initial state
    parameter LFSR_INIT = {LFSR_WIDTH{1'b1}},
    // LFSR configuration: "GALOIS", "FIBONACCI"
    parameter LFSR_CONFIG = "FIBONACCI",
    // bit-reverse input and output
    parameter REVERSE = 0,
    // invert input
    parameter INVERT = 1,
    // width of data input and output
    parameter DATA_WIDTH = 8,
    // implementation style: "AUTO", "LOOP", "REDUCTION"
    parameter STYLE = "AUTO"
)
(
    input  wire                    clk,
    input  wire                    rst,
    input  wire [DATA_WIDTH-1:0]   data_in,
    input  wire                    data_in_valid,
    output wire [DATA_WIDTH-1:0]   data_out
);

reg [LFSR_WIDTH-1:0] state_reg = LFSR_INIT;
reg [DATA_WIDTH-1:0] output_reg = 0;

wire [DATA_WIDTH-1:0] lfsr_data;
wire [LFSR_WIDTH-1:0] lfsr_state;

assign data_out = output_reg;

lfsr #(
    .LFSR_WIDTH(LFSR_WIDTH),
    .LFSR_POLY(LFSR_POLY),
    .LFSR_CONFIG(LFSR_CONFIG),
    .LFSR_FEED_FORWARD(1),
    .REVERSE(REVERSE),
    .DATA_WIDTH(DATA_WIDTH),
    .STYLE(STYLE)
)
lfsr_inst (
    .data_in(INVERT ? ~data_in : data_in),
    .state_in(state_reg),
    .data_out(lfsr_data),
    .state_out(lfsr_state)
);

always @(posedge clk) begin
    if (rst) begin
        state_reg <= LFSR_INIT;
        output_reg <= 0;
    end else begin
        if (data_in_valid) begin
            state_reg <= lfsr_state;
            output_reg <= lfsr_data;
        end
    end
end

endmodule
